#ifndef TRLOGGER_HPP
#define TRLOGGER_HPP

#include <direct.h>
#include <iostream>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/daily_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>

using namespace std;

#ifdef _WIN32
#define __FILENAME__ (strrchr(__FILE__, '\\') ? (strrchr(__FILE__, '\\') + 1):__FILE__)
#else
#define __FILENAME__ (strrchr(__FILE__, '/') ? (strrchr(__FILE__, '/') + 1):__FILE__)
#endif

#ifndef SUFFIX
#define SUFFIX(msg)  std::string(msg).append("  <")\
        .append(__FILENAME__).append("> <").append(__func__)\
        .append("> <").append(std::to_string(__LINE__))\
        .append(">").c_str()
#endif

class TrLogger
{

public:
    static TrLogger& GetInstance() {
        static TrLogger m_instance;
        return m_instance;
    }

    auto GetLogger() { return nml_logger; }

private:
    TrLogger() {
        if (::_access("logs", 0) == -1) {
            ::_mkdir("logs");
        }

        //设置为异步日志
        //spdlog::set_async_mode(32768);  // 必须为 2 的幂
        std::vector<spdlog::sink_ptr> sinkList;
        //#ifdef _CONSOLE
#ifdef _DEBUG
        auto consoleSink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
        consoleSink->set_level(spdlog::level::trace);
        //consoleSink->set_pattern("[multi_sink_example] [%^%l%$] %v");
        consoleSink->set_pattern("[%m-%d %H:%M:%S.%e][%^%L%$] %v");
        sinkList.push_back(consoleSink);
#endif
        auto basicSink = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logs/daily.log", 0, 0);
        basicSink->set_level(spdlog::level::debug);
        basicSink->set_pattern("[%Y-%m-%d %H:%M:%S.%e][%^%5l%$] %v");
        sinkList.push_back(basicSink);
        nml_logger = std::make_shared<spdlog::logger>("both", begin(sinkList), end(sinkList));
        //register it if you need to access it globally
        spdlog::register_logger(nml_logger);

        // 设置日志记录级别
#ifdef _DEBUG
        nml_logger->set_level(spdlog::level::debug);
#else
        nml_logger->set_level(spdlog::level::err);
#endif
        //设置当出发 err 或更严重的错误时立刻刷新日志到  disk
        nml_logger->flush_on(spdlog::level::err);
        spdlog::flush_every(std::chrono::seconds(3));
    }

    ~TrLogger() {
        spdlog::drop_all();
    }

    TrLogger(const TrLogger&) = delete;
    TrLogger& operator=(const TrLogger&) = delete;

private:
    std::shared_ptr<spdlog::logger> nml_logger;
};


#define TrTrace(msg,...) TrLogger::GetInstance().GetLogger()->trace(SUFFIX(msg),__VA_ARGS__)
#define TrDebug(...) TrLogger::GetInstance().GetLogger()->debug(__VA_ARGS__)
#define TrInfo(...) TrLogger::GetInstance().GetLogger()->info(__VA_ARGS__)
#define TrWarn(...) TrLogger::GetInstance().GetLogger()->warn(__VA_ARGS__)
#define TrError(...) TrLogger::GetInstance().GetLogger()->error(__VA_ARGS__)
#define TrCritical(...) TrLogger::GetInstance().GetLogger()->critical(__VA_ARGS__)

#define criticalif(b, ...)                        \
    do {                                       \
        if ((b)) {                             \
           BtLogger::GetInstance().GetLogger()->critical(__VA_ARGS__); \
        }                                      \
    } while (0)

#ifdef WIN32
#define errcode WSAGetLastError()
#endif

#endif // TRLOGGER_HPP
